#include"cli.h"
#include"tcpClient.h"
#include"logger.h"
#include"msg.h"
#include"public.h"

#include<string>
#include<iostream>
#include<memory>
#include<mutex>
#include<unordered_map>
#include<functional>
#include<string.h>
#include<unistd.h>
#include<fcntl.h>


Cli::Cli(std::string ip,size_t port):cli_(IpAddressPort(ip,port))
{

}
 std::shared_ptr<Cli> Cli:: GetInstance(std::string ip,size_t port)
{
   if(!Cli::cliInstance_)
   {
      std::unique_lock<std::mutex> pmutex(mutex_);
   }
   if(!Cli::cliInstance_)
   {
     Cli::cliInstance_ = std::shared_ptr<Cli>(new Cli(ip,port));
   }
   return cliInstance_;
}
void Cli::LsFile(std::string sendCmd)
{
  
  int sendByteofMeg = cli_.SendMsg(sendCmd);
  if(sendByteofMeg <= 0)
  {
    LOG_INFO <<"erro disconnect";
   return ;
  }
   
     Msg msg = cli_.RecvMsg();
   if("#erro pipe" ==  msg.msg_.substr(0,10))//收到消息头部时要检查是正确还是出错
   {
     LOG_ERROR<<"#erro pipe";
       return ;
   }else if("#erro fork" == msg.msg_.substr(0,10))
   {
      LOG_ERROR<<"#erro fork";
   }
   else if("#ok" == msg.msg_.substr(0,3))
   {
        std::cout<<msg.msg_.substr(3,msg.msg_.size());
   }
   return ;

}
void Cli::GetFile(std::string sendCmd,std::string cmdParameter)
{
  int sendByteofMsg = cli_.SendMsg(sendCmd);
  if(sendByteofMsg <=0)
  {
    LOG_ERROR<<"send erro";
    return ;
  }
   Msg msg = cli_.RecvMsg();
   if(msg.numberOfRecvBytes_ <=0)
   {
      LOG_ERROR<<"ser erro close";
      exit(1);
   }else if("#erro open file failed" == msg.msg_.substr(0,22))
   {
         LOG_INFO <<"please input correct filename";
         return ;
   }else if("#erro lseek file failed" == msg.msg_.substr(0,23))
   {
      LOG_ERROR<<"lseek file failed";
      return ;
   }
    chdir("../localfile");
  int fd = open(cmdParameter.c_str(),O_WRONLY|O_CREAT,0600);//还可以先看本地是否有，如果存在的话，则在后面继续写，（断点续传），也可以重新创建一个
  if(-1 == fd)
  {
    cli_.SendMsg("#erro");
    LOG_ERROR<<strerror(errno);
  }else
  {
    cli_.SendMsg("#ok");
  }
  
  int filesize = atoi(msg.msg_.c_str()+3);
  std::cout<<"下载的文件:"<<cmdParameter<< "大小为"<<filesize<<std::endl;
   if(0 == filesize)
   {
      return ;
   }
  int currFileSize =0;
  while(1)
  {
    msg = cli_.RecvMsg();
    if(msg.numberOfRecvBytes_ <=0)
    {
        std::cout<<"Ser close"<<std::endl;
        break;
    }
    write(fd,msg.msg_.c_str(),msg.numberOfRecvBytes_);
    currFileSize+= msg.numberOfRecvBytes_;
    float f = currFileSize*100.0 /filesize;
    printf("down:%.2f%%",f);
    fflush(stdout);

    if( currFileSize >= filesize)
    {
        printf("\n文件下载完成\n");
        break;
    }
  }
  close(fd);
}
void Cli:: UpFile(std::string sendCmd,std::string cmdParameter)
{
  
  int sendByteofMsg = cli_.SendMsg(sendCmd);
  if(sendByteofMsg <=0)
  {
    LOG_ERROR<<"send erro";
    return ;
  }
   chdir("../localfile");
   int fd = open(cmdParameter.c_str(),O_RDONLY);
   if(-1 == fd)
   {
     LOG_ERROR<<"open "<<cmdParameter<<" erro";
     return ;
   }
   int filesize = lseek(fd,0,SEEK_END);
   if(-1 == filesize)
   {
      LOG_ERROR<<"leek"<<cmdParameter<<" erro";
   }
   lseek(fd,0,SEEK_SET);
   char statusBuff[SMALL_BUF_LEN] ={"#ok"};
   sprintf(statusBuff+3,"%d",filesize);
   sendByteofMsg = cli_.SendMsg(statusBuff);
   if(sendByteofMsg <= 0)
   {
      LOG_ERROR<<"send erro";
   }
   memset(statusBuff,0,SMALL_BUF_LEN);
   Msg msg = cli_.RecvMsg(); 
   if(msg.numberOfRecvBytes_ <=0)
   {
      LOG_ERROR<<"ser erro close";
   }
   if("#ok" != msg.msg_.substr(0,3))
   {
     LOG_ERROR<<"up filed";
   }
   char data[LAGE_BUF_LEN] ={0};
   int theNumofRead =0;
   while((theNumofRead = read(fd,data,LAGE_BUF_LEN))>0)
   {
     cli_.SendMsg(data);
   }
   msg = cli_.RecvMsg();
   if(msg.numberOfRecvBytes_ <=0 )
   {
      LOG_ERROR<<"ser erro close";
   }else if("#erro up file failed" == msg.msg_.substr(0,20))
   {
      LOG_ERROR<<"up filed";
   }else
   {
      LOG_INFO<<"up seccess";
   }
   close(fd);
   return ;

}
void Cli:: DeleteFile(std::string sendCmd,std::string cmdParameter)
{
  int sendByteofMsg = cli_.SendMsg(sendCmd);
  if(sendByteofMsg <=0)
  {
    LOG_ERROR<<"send erro";
    return ;
  }
   Msg msg = cli_.RecvMsg();
   if(msg.numberOfRecvBytes_ <=0)
   {
      LOG_ERROR<<"ser erro close";
      exit(1);
   }else if("#erro" == msg.msg_.substr(0,5))
   {
         LOG_INFO <<"please input correct filename";
         return ;
   }else
   {
      LOG_INFO<<"delete success";
   }
}
 std::shared_ptr<Cli> Cli:: cliInstance_=nullptr;
 std::mutex Cli::mutex_;

int main()
{
    std::shared_ptr<Cli> cli = Cli::GetInstance("127.0.0.1",8001);
  
    while(1)
    {
        char buff[128]={0};
        fflush(stdin);
         std::cout<<"connect>>"<<std::endl;
         std::cout<<"please input"<<std::endl;
         fgets(buff,127,stdin);          
         buff[strlen(buff)-1] =0;
         std::string sendbuff(buff);

         char * myargv[10] ={0};
         int i=0;
         char *s =strtok(buff," ");
         while(NULL != s)
         {
            myargv[i++] =s;
            s = strtok(NULL," ");
         }
         char * cmd = myargv[0];
         
         if(NULL != myargv[2] || NULL == cmd)
         {
            std::cout<<"cmd error"<<std::endl;
            continue;
         }else if(strcmp(cmd,"exit")==0)
         {
            break;

         }else if(strcmp(cmd,"ls")==0)
         {
            if(NULL != myargv[1])
            {
              std::cout<<"cmd error"<<std::endl;
              continue;
            }
            cli->LsFile(sendbuff);
         }else if(strcmp(cmd,"get")==0)
         {
            if(NULL == myargv[1])
            {
              std::cout<<"cmd error"<<std::endl;
              continue;
            }
            cli->GetFile(sendbuff,myargv[1]);
         }else if(strcmp(cmd,"up")==0)
         {
             if(NULL == myargv[1])
            {
              std::cout<<"cmd error"<<std::endl;
              continue;
            }
            cli->UpFile(sendbuff,myargv[1]);
           
         }else if(strcmp(cmd,"delete")==0)
         {
             if(NULL == myargv[1])
            {
              std::cout<<"cmd error"<<std::endl;
              continue;
            }
           cli->DeleteFile(sendbuff,myargv[1]);
         }else
         {
             std::cout<<"input erro"<<std::endl;
             continue;
         }
    }

    exit(0);
}